package com.txsj.scan.utils;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import com.txsj.scan.MyApplication;
import com.txsj.scan.R;
import com.zebra.adc.decoder.BarCodeReader;

/**
 * @Created by WangChuangJun on 2018/12/14
 * @Describe 红外线扫描条码
 *
 * 例如：
 * SDLguiUtils.getInstance(this).setListener(new SDLguiUtils.OnScanListener() {
 *             @Override
 *             public void onScanSuccess(String data) {
 *                 Trace.e("wcj:扫描回调=========:" + data);
 *                 isQrCodeOrScanCode(data);
 *             }
 *
 *             @Override
 *             public void onScanError(String errorMsg) {
 *                 Trace.e("wcj:扫描失败=========:"+errorMsg);
 *                 showErrorMsg(errorMsg);
 *             }
 *         }).doDecode();
 *
 * 注意 :
 *      1. 调用异常：扫描需要相机权限，请在使用SDLguiUtils前进行权限申请
 *      2. 在当前Activity生命回调onPause方法的时候调用
 *          @Override
 *          protected void onPause() {
 *               super.onPause();
 *               if (SDLguiUtils.getInstance(this).getState() == 1) {//如果当前正在扫描，先关闭扫描
 *                  SDLguiUtils.getInstance(this).doDecode();
 *               }
 *              SDLguiUtils.getInstance(this).onPause();//确保关闭扫描后进行onPause()回调
 *          }
 */
public class SDLguiUtils implements BarCodeReader.DecodeCallback, BarCodeReader.PictureCallback, BarCodeReader.PreviewCallback,
        BarCodeReader.VideoCallback, BarCodeReader.ErrorCallback {

    // ------------------------------------------------------
    static final private boolean saveSnapshot = false; // true = save snapshot to file
    static private boolean sigcapImage = true; // true = display signature capture
    static private boolean videoCapDisplayStarted = false;
    //states
    static final int STATE_IDLE = 0;
    static final int STATE_DECODE = 1;
    static final int STATE_HANDSFREE = 2;
    static final int STATE_PREVIEW = 3;    //snapshot preview mode
    static final int STATE_SNAPSHOT = 4;
    static final int STATE_VIDEO = 5;

    // -----------------------------------------------------
    // ui
    private TextView tvStat = null;
    private TextView tvData = null;
    private EditText edPnum = null;
    private EditText edPval = null;
    private CheckBox chBeep_RP = null;

    private ImageView image = null;    //snaphot image screen

    private SurfaceView surfaceView = null;    //video screen
    private SurfaceHolder surfaceHolder = null;
    private LayoutInflater controlInflater = null;

    // system
    private ToneGenerator tg = null;

    // BarCodeReader specifics
    private BarCodeReader bcr = null;

    private boolean beepMode = true;        // decode beep enable
    private int Mobile_reading_pane = 716;        // Mobile Phone reading Pane
    private int reading_pane_value = 1;
    private boolean snapPreview = false;        // snapshot preview mode enabled - true - calls viewfinder which gets handled by
    private int trigMode = BarCodeReader.ParamVal.LEVEL;
    private boolean atMain = false;

    public int getState() {
        return state;
    }

    private int state = STATE_IDLE;
    private int decodes = 0;

    private int motionEvents = 0;
    private int modechgEvents = 0;

    private int snapNum = 0;        //saved snapshot #
    private String decodeDataString;
    private String decodeStatString;
    private static int decCount = 0;

    //add for test
    private long mStartTime;
    private long mBarcodeCount = 0;
    private long mConsumTime;


    static {
        System.loadLibrary("IAL");
        System.loadLibrary("SDL");

        if (android.os.Build.VERSION.SDK_INT >= 19)
            System.loadLibrary("barcodereader44"); // Android 4.4
        else if (android.os.Build.VERSION.SDK_INT >= 18)
            System.loadLibrary("barcodereader43"); // Android 4.3
        else
            System.loadLibrary("barcodereader");   // Android 2.3 - Android 4.2
    }

    // -----------------------------------------------------
    // statics
    private static Activity app = null;
    private static SDLguiUtils instance = null;

    // -----------------------------------------------------
    private SDLguiUtils() {
        // sound
        tg = new ToneGenerator(AudioManager.STREAM_MUSIC, ToneGenerator.MAX_VOLUME);
        openConnect();
    }

    public static SDLguiUtils getInstance(Activity context) {
        app = context;
        if (null == instance)
            instance = new SDLguiUtils();
        if (null == instance.bcr){
            instance.openConnect();
        }
        return instance;
    }

    /**
     * 进行连接
     */
    private void openConnect() {
        state = STATE_IDLE;
        try {

            int num = BarCodeReader.getNumberOfReaders();
            // todo 展示
//            dspStat(getResources().getString(R.string.app_name) + " v" + this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName);
            Trace.e(app.getResources().getString(R.string.app_name) + " v" + app.getPackageManager().getPackageInfo(app.getPackageName(), 0).versionName);
            if (android.os.Build.VERSION.SDK_INT >= 18)
                bcr = BarCodeReader.open(num, MyApplication.getInstance()); // Android 4.3 and above
            else
                bcr = BarCodeReader.open(num); // Android 2.3

            if (bcr == null) {
                //展示
//                dspErr("open failed");
                Trace.e("open failed");
                return;
            }

            bcr.setDecodeCallback(this);

            bcr.setErrorCallback(this);

            // Set parameter - Uncomment for QC/MTK platforms
            bcr.setParameter(765, 0); // For QC/MTK platforms
            bcr.setParameter(764, 3);

            // Set Orientation
            bcr.setParameter(687, 4); // 4 - omnidirectional
        } catch (Exception e) {
            //TODO 展示
//            dspErr("open excp:" + e);
            Trace.e("open excp:" + e);
        }
    }

    //-----------------------------------------------------

    /**
     * 暂停，与调用该Utils的activity生命周期相同
     */
    public void onPause() {
        if (bcr != null) {
            setIdle();
            bcr.release();
            bcr = null;
        }
    }

    //------------------------------------------
    private int setIdle() {
        int prevState = state;
        int ret = prevState;        //for states taking time to chg/end

        state = STATE_IDLE;
        switch (prevState) {
            case STATE_HANDSFREE:
                resetTrigger();
                //fall thru
            case STATE_DECODE:
                // todo 展示
//                dspStat("decode stopped");
                if (null != listener) listener.onScanError("decode stopped");
                bcr.stopDecode();
                break;

            case STATE_VIDEO:
                bcr.stopPreview();
                break;

            case STATE_SNAPSHOT:
                ret = STATE_IDLE;
                break;

            default:
                ret = STATE_IDLE;
        }
        return ret;
    }


    // ----------------------------------------
    // start a decode session

    /**
     * 扫描结束或开始
     */
    public void doDecode() {
        if (setIdle() != STATE_IDLE)
            return;

        state = STATE_DECODE;
        decCount = 0;
        decodeDataString = new String("");
        decodeStatString = new String("");
        // todo 展示
//        if (null != listener) listener.onScanError("");
//        dspData("");
//        dspStat(R.string.decoding);
        try {
            mStartTime = System.currentTimeMillis();
            bcr.startDecode(); // start decode (callback gets results)
        } catch (Exception e) {
            // todo 展示
            if (null != listener) listener.onScanError(e.getMessage());
//            dspErr("open excp:" + e);
        }
    }


    @Override
    public void onDecodeComplete(int symbology, int length, byte[] data, BarCodeReader reader) {
        if (state == STATE_DECODE)
            state = STATE_IDLE;

        // Get the decode count
        if (length == BarCodeReader.DECODE_STATUS_MULTI_DEC_COUNT)
            decCount = symbology;

        if (length > 0) {
            if (isHandsFree() == false && isAutoAim() == false)
                bcr.stopDecode();

            ++decodes;

            if (symbology == 0x69)    // signature capture
            {
                if (sigcapImage) {
                    Bitmap bmSig = null;
                    int scHdr = 6;
                    if (length > scHdr)
                        bmSig = BitmapFactory.decodeByteArray(data, scHdr, length - scHdr);

//                    if (bmSig != null)
//                        snapScreen(bmSig);

                    else
                        //TODO 展示
//                        dspErr("OnDecodeComplete: SigCap no bitmap");
                        Trace.e("OnDecodeComplete: SigCap no bitmap");
                }
                decodeStatString += new String("[" + decodes + "] type: " + symbology + " len: " + length);
                decodeDataString += new String(data);

                mBarcodeCount++;
                long consum = System.currentTimeMillis() - mStartTime;
                mConsumTime += consum;
                decodeDataString += "\n\r" + "本次消耗时间:" + consum + "毫秒" + "\n\r" + "平均速度:" + (mConsumTime / mBarcodeCount) + "毫秒/个";
				/*try {
					decodeDataString += new String(data,charsetName(data));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}*/
            } else {


                if (symbology == 0x99)    //type 99?
                {
                    symbology = data[0];
                    int n = data[1];
                    int s = 2;
                    int d = 0;
                    int len = 0;
                    byte d99[] = new byte[data.length];
                    for (int i = 0; i < n; ++i) {
                        s += 2;
                        len = data[s++];
                        System.arraycopy(data, s, d99, d, len);
                        s += len;
                        d += len;
                    }
                    d99[d] = 0;
                    data = d99;
                }

//                Log.d("012", "ret="+byte2hex(data));
//                decodeStatString += new String("[" + decodes + "] type: " + symbology + " len: " + length);

                decodeDataString += new String(filterEndZero(data));
                //add for test speed
                mBarcodeCount++;
//                long consum = System.currentTimeMillis() - mStartTime;
//                mConsumTime += consum;
//                decodeDataString += "\n\r" + "本次消耗时间:" + consum + "毫秒" + "\n\r" +  "平均速度:" + (mConsumTime / mBarcodeCount) + "毫秒/个";
                // todo 展示
//                dspStat(decodeStatString);
//                dspData(decodeDataString);
                if (null != listener) listener.onScanSuccess(decodeDataString);

                if (decCount > 1) // Add the next line only if multiple decode
                {
                    decodeStatString += new String(" ; ");
                    decodeDataString += new String(" ; ");
                } else {
                    decodeDataString = new String("");
                    decodeStatString = new String("");
                }
            }

        } else    // no-decode
        {
            // todo 展示
//            if (null != listener) listener.onScanError("");
//            dspData("");
            switch (length) {
                case BarCodeReader.DECODE_STATUS_TIMEOUT:
                    // todo 展示
//                    dspStat("decode timed out");
                    if (null != listener) listener.onScanError("decode timed out");
                    break;

                case BarCodeReader.DECODE_STATUS_CANCELED:
                    // todo 展示
//                    dspStat("decode cancelled");
                    if (null != listener) listener.onScanError("decode cancelled");
                    break;

                case BarCodeReader.DECODE_STATUS_ERROR:
                    // todo 展示
                default:
//                    dspStat("decode failed");
//                    if (null != listener) listener.onScanError("decode failed");
                    break;
            }
        }
    }

    /**
     * 去掉末尾为0的元素
     * @param data
     * @return
     */
    private byte[] filterEndZero(byte[] data) {
        Trace.e("wcj:还未去零========="+new String(data));
        int count = 0;
        for (int i = data.length - 1; i >= 0; i--) {
            if (data[i] == 0) {
                count++;
            } else {
                break;
            }
        }
        byte[] newData = new byte[data.length - count];
        for (int j = 0; j <= data.length - count - 1; j++) {
            newData[j] = data[j];
        }
        return newData;
    }

    @Override
    public void onEvent(int event, int info, byte[] data, BarCodeReader reader) {

    }

    @Override
    public void onPictureTaken(int format, int width, int height, byte[] data, BarCodeReader reader) {

    }

    @Override
    public void onVideoFrame(int format, int width, int height, byte[] data, BarCodeReader reader) {

    }

    @Override
    public void onPreviewFrame(byte[] data, BarCodeReader reader) {

    }

    @Override
    public void onError(int error, BarCodeReader reader) {

    }

// ==== SDL methods =====================

    // ----------------------------------------
    private boolean isHandsFree() {
        return (trigMode == BarCodeReader.ParamVal.HANDSFREE);
    }

    // ----------------------------------------
    private boolean isAutoAim() {
        return (trigMode == BarCodeReader.ParamVal.AUTO_AIM);
    }

    // ----------------------------------------
    // reset Level trigger mode
    void resetTrigger() {
        doSetParam(BarCodeReader.ParamNum.PRIM_TRIG_MODE, BarCodeReader.ParamVal.LEVEL);
        trigMode = BarCodeReader.ParamVal.LEVEL;
    }

    // ----------------------------------------
    // set param
    private int doSetParam(int num, int val) {
        String s = "";
        int ret = bcr.setParameter(num, val);
        if (ret != BarCodeReader.BCR_ERROR) {
            if (num == BarCodeReader.ParamNum.PRIM_TRIG_MODE) {
                trigMode = val;
                if (val == BarCodeReader.ParamVal.HANDSFREE) {
                    s = "HandsFree";
                } else if (val == BarCodeReader.ParamVal.AUTO_AIM) {
                    s = "AutoAim";
                    ret = bcr.startHandsFreeDecode(BarCodeReader.ParamVal.AUTO_AIM);
                    if (ret != BarCodeReader.BCR_SUCCESS) {
                        // todo 展示
                        if (null != listener) listener.onScanError("AUtoAIm start FAILED");
//                        dspErr("AUtoAIm start FAILED");
                    }
                } else if (val == BarCodeReader.ParamVal.LEVEL) {
                    s = "Level";
                }
            } else if (num == BarCodeReader.ParamNum.IMG_VIDEOVF) {
                if (snapPreview = (val == 1))
                    s = "SnapPreview";
            }
        } else
            s = " FAILED (" + ret + ")";

        // todo 展示
//        dspStat("Set #" + num + " to " + val + " " + s);
        return ret;
    }

    private String byte2hex(byte[] buffer) {
        String h = "";

        for (int i = 0; i < buffer.length; i++) {
            String temp = Integer.toHexString(buffer[i] & 0xFF);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            h = h + " " + temp;
        }

        return h;

    }

    private OnScanListener listener;

    public SDLguiUtils setListener(OnScanListener listener) {
        this.listener = listener;
        return instance;
    }

    public interface OnScanListener {
        void onScanSuccess(String data);

        void onScanError(String msg);
    }
}
